#pragma once

/**
* A macro to compare members of two drawing policies(A and B), and return based on the result.
* If the members are the same, the macro continues execution rather than returning to the caller.
*/
#define COMPAREDRAWINGPOLICYMEMBERS(MemberName) \
	if(A.MemberName < B.MemberName) { return -1; } \
	else if(A.MemberName > B.MemberName) { return +1; }


namespace RenderSystem
{
	class SubMeshInstance;
	class VertexFactory;
	class MaterialInstance;

	class MeshDrawingPolicy
	{
	public:

		struct ElementDataType {};

		MeshDrawingPolicy( const VertexFactory* pVertexFactory, const MaterialInstance* pMaterialInstance );

		DWORD GetTypeHash() const
		{
			return PointerHash(VertexFactory);
		}

		bool Matches(const MeshDrawingPolicy& OtherDrawer) const
		{
			return
				VertexFactory == OtherDrawer.VertexFactory &&
				MaterialRenderProxy == OtherDrawer.MaterialRenderProxy &&
				bIsTwoSidedMaterial == OtherDrawer.bIsTwoSidedMaterial && 
				bIsWireframeMaterial == OtherDrawer.bIsWireframeMaterial;
		}

		/**
		* Sets the render states for drawing a mesh.
		* @param PrimitiveSceneInfo - The primitive drawing the dynamic mesh.  If this is a view element, this will be NULL.
		*/
		void SetMeshRenderState(
			const FSceneView& View,
			const FPrimitiveSceneInfo* PrimitiveSceneInfo,
			const FMeshElement& Mesh,
			bool bBackFace,
			const ElementDataType& ElementData
			) const;

		/**
		* Executes the draw commands for a mesh.
		*/
		virtual void DrawMesh(const SubMeshInstance& SubMeshInstance ) const;

		void DrawShared( void ) const;

		/**
		* Get the decl and stream strides for this mesh policy type and vertexfactory
		* @param VertexDeclaration - output decl 
		* @param StreamStrides - output array of vertex stream strides 
		*/
		void GetVertexDeclarationInfo(FVertexDeclarationRHIRef& VertexDeclaration, DWORD *StreamStrides) const;

		friend INT Compare(const MeshDrawingPolicy& A,const MeshDrawingPolicy& B)
		{
			COMPAREDRAWINGPOLICYMEMBERS(VertexFactory);
			COMPAREDRAWINGPOLICYMEMBERS(MaterialRenderProxy);
			return 0;
		}

		// Accessors.
		bool IsTwoSided() const
		{
			return bIsTwoSidedMaterial;
		}
		bool IsWireframe() const
		{
			return bIsWireframeMaterial;
		}
		bool NeedsBackfacePass() const
		{
			return bNeedsBackfacePass;
		}

	protected:
		const VertexFactory* m_pVertexFactory;
		const MaterialInstance* m_pMaterialInstance;
	};
}